package com.asset.dispoal.file.evidenceRecognition.rar;

import com.asset.dispoal.business.bsCase.domain.db.entity.BsCaseDisposalFile;
import lombok.extern.slf4j.Slf4j;
import net.sf.sevenzipjbinding.ExtractAskMode;
import net.sf.sevenzipjbinding.ExtractOperationResult;
import net.sf.sevenzipjbinding.IArchiveExtractCallback;
import net.sf.sevenzipjbinding.IInArchive;
import net.sf.sevenzipjbinding.ISequentialOutStream;
import net.sf.sevenzipjbinding.PropID;
import net.sf.sevenzipjbinding.SevenZipException;
import tech.mhuang.pacebox.core.id.BaseIdeable;
import tech.mhuang.pacebox.core.id.SnowflakeIdeable;
import tech.mhuang.pacebox.springboot.core.spring.start.SpringContextHolder;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * Rar解压回调类
 *
 * @author: yf
 * @date: 2022-08-22 08:04:19
 */
@Slf4j
public class ExtractCallback implements IArchiveExtractCallback {
    /**
     * 文件记录防止重复解压
     */
    private final Map<String, String> fileMap = new ConcurrentHashMap<String, String>();

    BaseIdeable<String> snowFlake = SpringContextHolder.getBean("snowflake", SnowflakeIdeable.class);

    private int index;
    private IInArchive inArchive;
    private String outDir;
    private String outIgnoreHeadPath;
    private String generateId;
    private List<BsCaseDisposalFile> fileList;

    public ExtractCallback(IInArchive inArchive, String outDir, String outIgnoreHeadPath, String generateId) {
        this.inArchive = inArchive;
        this.outDir = outDir;
        this.outIgnoreHeadPath = outIgnoreHeadPath;
        this.generateId = generateId;
        fileList = new ArrayList<BsCaseDisposalFile>();
    }

    @Override
    public void setCompleted(long arg0) throws SevenZipException {
    }

    @Override
    public void setTotal(long arg0) throws SevenZipException {
    }

    @Override
    public ISequentialOutStream getStream(int index, ExtractAskMode extractAskMode) throws SevenZipException {
        this.index = index;
        final String path = (String) inArchive.getProperty(index, PropID.PATH);
        final boolean isFolder = (boolean) inArchive.getProperty(index, PropID.IS_FOLDER);
        return new ISequentialOutStream() {
            @Override
            public int write(byte[] data) throws SevenZipException {
                try {
                    if (!isFolder) {
                        //文件后缀
                        String fileExtension = path.substring(path.lastIndexOf("."));
                        //原文件名称
                        String orinionName = path.substring(path.lastIndexOf(File.separator) + 1);
                        //压缩包根基目录
                        String parentName = path.substring(0, path.lastIndexOf(File.separator));

                        //文件全路径
                        Path allPath = Paths.get(outDir, parentName);
                        if (!Files.exists(allPath)) {
                            Files.createDirectories(allPath);
                        }

                        String pathTo = "";
                        if (fileMap.containsKey(path)) {
                            log.debug("文件追加-----");
                            pathTo = fileMap.get(path);
                            save2File(pathTo, data, true);
                        } else {
                            log.debug("文件新增-----");
                            String suffixId = snowFlake.generateId();
                            String fileName = generateId + "_" + orinionName.replace(orinionName, suffixId + "&" + orinionName).replace("#", "");
                            String replaceIgnoreHeadFileName = Paths.get(outIgnoreHeadPath, parentName, fileName).toString();
                            pathTo = Paths.get(allPath.toString(), fileName).toString();
                            save2File(pathTo, data, false);
                            fileMap.put(path, pathTo);
                            fileMap.put("outIgnoreHeadPath" + path, replaceIgnoreHeadFileName);
                        }

                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
                return data.length;
            }
        };
    }

    @Override
    public void prepareOperation(ExtractAskMode arg0) throws SevenZipException {
    }

    @Override
    public void setOperationResult(ExtractOperationResult extractOperationResult) throws SevenZipException {
        String path = (String) inArchive.getProperty(index, PropID.PATH);
        boolean isFolder = (boolean) inArchive.getProperty(index, PropID.IS_FOLDER);

        //將提取結果存入庫，不爲文件夾
        if (!isFolder) {
            String unRarFilePath = fileMap.get(path);
            String orinionName = path.substring(path.lastIndexOf(File.separator) + 1);
            String replaceName = unRarFilePath.substring(unRarFilePath.lastIndexOf(File.separator) + 1);
            String outIgnoreHeadPath = fileMap.get("outIgnoreHeadPath" + path);
            log.debug("提取文件结果, 原文件名称:{}", orinionName);
            log.debug("提取文件结果, 现文件名称:{}", replaceName);
            log.debug("提取文件结果, 现在文件路径:{}", unRarFilePath);
            log.debug("outIgnoreHeadPath:{}", fileMap.get("outIgnoreHeadPath" + path));
            //判断是否为压缩文件
            final String fileType = unRarFilePath.substring(unRarFilePath.lastIndexOf(".") + 1);
            String currentPath = unRarFilePath.substring(0, unRarFilePath.lastIndexOf(File.separator));
            if ("rar".equals(fileType) || "zip".equals(fileType)) {
                List<BsCaseDisposalFile> childFileList = FileDecUtils.unRar(unRarFilePath, currentPath, outIgnoreHeadPath, generateId);
                this.fileList.addAll(childFileList);
            } else {
                BsCaseDisposalFile caseDisposalFile = new BsCaseDisposalFile();
                caseDisposalFile.setId(snowFlake.generateId());
                caseDisposalFile.setOriginalName(orinionName);
                caseDisposalFile.setReplaceName(replaceName);
                caseDisposalFile.setFilePath(outIgnoreHeadPath);
                caseDisposalFile.setUploadWay("1");
                this.fileList.add(caseDisposalFile);
            }
        }


    }

    public List<BsCaseDisposalFile> getFileList() {
        return this.fileList;
    }

    private boolean save2File(String path, byte[] msg, boolean append) {
        try (RandomAccessFile accessFile = new RandomAccessFile(path, "rw")) {
            if (append) {
                accessFile.seek(accessFile.length());
            }
            accessFile.write(msg);
            return true;
        } catch (FileNotFoundException e) {
            e.printStackTrace();
            return false;
        } catch (IOException e) {
            e.printStackTrace();
            return false;
        }
    }
}
